/*
 * Copyright (c) 2017-present, CV4J Contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cv4j.core.datamodel;

import com.cv4j.exception.CV4JException;

/**
 * ColorProcessor
 *
 * @since 2021-07-22
 */
public class ColorProcessor implements ImageProcessor {
    private byte[] R1;
    private byte[] G1;
    private byte[] B1;
    private ImageData image;

    private int width;
    private int height;

    public ColorProcessor(int width, int height) {
        this.width = width;
        this.height = height;
        int size = width * height;
        R1 = new byte[size];
        G1 = new byte[size];
        B1 = new byte[size];
    }


    public ColorProcessor(int[] pixels, int width, int height) {
        this.width = width;
        this.height = height;
        int size = width * height;
        R1 = new byte[size];
        G1 = new byte[size];
        B1 = new byte[size];
        backFillData(pixels);
    }

    private void backFillData(int[] input) {
        int c1 = 0;
        int r1 = 0;
        int g1 = 0;
        int b1 = 0;
        int length = input.length;
        for (int i = 0; i < length; i++) {
            c1 = input[i];
            r1 = (c1 & 0xff0000) >> 16;
            g1 = (c1 & 0xff00) >> 8;
            b1 = c1 & 0xff;
            R1[i] = (byte) r1;
            G1[i] = (byte) g1;
            B1[i] = (byte) b1;
        }
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public int getHeight() {
        return height;
    }

    @Override
    public int getChannels() {
        return 3;
    }

    /**
     * getRed
     *
     * @return byte
     */
    public byte[] getRed() {
        return R1;
    }

    /**
     * getGreen
     *
     * @return byte
     */
    public byte[] getGreen() {
        return G1;
    }

    /**
     * getBlue
     *
     * @return byte
     */
    public byte[] getBlue() {
        return B1;
    }

    @Override
    public void getPixel(int row, int col, byte[] rgb) {
        int index = row * width + col;
        if (rgb != null && rgb.length == 3) {
            rgb[0] = R1[index];
            rgb[1] = G1[index];
            rgb[2] = B1[index];
        }
    }

    /**
     * putRGB
     *
     * @param red red
     * @param green green
     * @param blue blue
     */
    public void putRGB(byte[] red, byte[] green, byte[] blue) {
        System.arraycopy(red, 0, R1, 0, red.length);
        System.arraycopy(green, 0, G1, 0, green.length);
        System.arraycopy(blue, 0, B1, 0, blue.length);
    }

    /**
     * getPixels
     *
     * @return int
     */
    public int[] getPixels() {
        int size = width * height;
        int[] pixels = new int[size];
        for (int i = 0; i < size; i++) {
            pixels[i] = 0xff000000 | ((R1[i] & 0xff) << 16) | ((G1[i] & 0xff) << 8) | B1[i] & 0xff;
        }
        return pixels;
    }

    /**
     * setCallBack
     *
     * @param data data
     */
    protected void setCallBack(ImageData data) {
        this.image = data;
    }

    public ImageData getImage() {
        return this.image;
    }

    @Override
    public float[] toFloat(int index) {
        if (index == 0) {
            float[] data = new float[R1.length];
            int length = data.length;
            for (int i = 0; i < length; i++) {
                data[i] = R1[i] & 0xff;
            }
            return data;
        } else if (index == 1) {
            float[] data = new float[G1.length];
            int length = data.length;
            for (int i = 0; i < length; i++) {
                data[i] = G1[i] & 0xff;
            }
            return data;
        } else if (index == 2) {
            float[] data = new float[B1.length];
            int length = data.length;
            for (int i = 0; i < length; i++) {
                data[i] = B1[i] & 0xff;
            }
            return data;
        } else {
            throw new CV4JException("invalid argument...");
        }
    }

    @Override
    public int[] toInt(int index) {
        if (index == 0) {
            int[] data = new int[R1.length];
            int length = data.length;
            for (int i = 0; i < length; i++) {
                data[i] = R1[i] & 0xff;
            }
            return data;
        } else if (index == 1) {
            int[] data = new int[G1.length];
            int length = data.length;
            for (int i = 0; i < length; i++) {
                data[i] = G1[i] & 0xff;
            }
            return data;
        } else if (index == 2) {
            int[] data = new int[B1.length];
            int length = data.length;
            for (int i = 0; i < length; i++) {
                data[i] = B1[i] & 0xff;
            }
            return data;
        } else {
            throw new CV4JException("invalid argument...");
        }
    }

    @Override
    public byte[] toByte(int index) {
        if (index == 0) {
            return R1;
        } else if (index == 1) {
            return G1;
        } else if (index == 2) {
            return B1;
        } else {
            throw new CV4JException("invalid argument...");
        }
    }
}
